/*
* Copyright 2010 Pavel Kozhin 
*
* Licensed under the Apache License, Version 2.0 (the "License"); 
* you may not use this file except in compliance with the License. 
* You may obtain a copy of the License at 
* 
* http://www.apache.org/licenses/LICENSE-2.0
* 
* Unless required by applicable law or agreed to in writing, software 
* distributed  under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
* See the License for the specific language governing permissions and 
* limitations under the License.
*
* Author: Pavel Kozhin.
*/

package org.bookmarksframework.navigation.state
{
	import flash.events.Event;
	import flash.events.EventDispatcher;
	
	import mx.collections.IList;
	
	import org.bookmarksframework.core.IDestroyable;
	
	[Event(name="conditionChange", type="org.bookmarksframework.navigation.events.NavigationConditionChangeEvent")]
	
	[Event(name="conditionValidate", type="org.bookmarksframework.navigation.events.NavigationConditionValidateEvent")]

	public class NavigationState extends EventDispatcher implements IDestroyable
	{
		protected var controller:IStateController;
		
		private var _id:String;
		
		[Bindable("propertyChange")]
		public function get id():String
		{
			return _id;
		}
		
		private var _paths:IList;

		[Bindable("propertyChange")]
		public function get paths():IList
		{
			return _paths;
		}
		
		private var _path:String;

		[Bindable("pathChanged")]
		public function get path():String
		{
			return _path;
		}
		
		private var _links:IList;

		[Bindable("linksChanged")]
		public function get links():IList
		{
			return _links;
		}
		
		[Bindable("propertyChange")]
		private var _link:StateLink = null;
		
		public function get link():StateLink
		{
			return _link;
		}
		
		private var _attributes:Object;

		[Bindable("propertyChange")]
		public function get attributes():Object
		{
			return _attributes;
		}
		
		private var _isValid:Boolean = true;
		
		[Bindable("isValidChanged")]
		public function get isValid():Boolean
		{
			return _isValid;
		}

		private var _data:* = null;
		
		[Bindable]
		public function get data():*
		{
			return _data;
		}

		public function set data(value:*):void
		{
			_data = value;
		}
		
		private var _strict:Boolean;

		public function get strict():Boolean
		{
			return _strict;
		}

		public function set strict(value:Boolean):void
		{
			_strict = value;
		}
		
		private var _enabled:Boolean = true;

		public function get enabled():Boolean
		{
			return _enabled;
		}

		public function set enabled(value:Boolean):void
		{
			_enabled = value;
		}
		
		public function match(path:String):Boolean
		{
			var p:String;
			
			for (var i:int = 0; i < paths.length; ++i)
			{
				p = paths.getItemAt(i) as String;
				
				if ((p == path) || (path.search(new RegExp(p + "$")) != -1))
					return true;
			}
			
			return false;
		}
		
		public function substitute(...args):String
		{
			var path:String;
			var matched:Array;
			var re:RegExp = new RegExp("\\(.+\\)", "g");
			var f:Function = function(...params):String
			{
				return args.shift(); 
			};
			
			for (var i:int = 0; i < paths.length; ++i)
			{
				path = paths.getItemAt(i) as String;
				if (!re.test(path))
					continue;
				
				matched = path.match(re);
				if (matched.length == args.length)
				{
					path = path.replace(re, f);
					return path;
				}
			}
			
			return paths.getItemAt(0) as String;
		}
		
		public function NavigationState(controller:IStateController, 
										id:String, path:String, paths:IList, 
										links:IList, strict:Boolean, enabled:Boolean,
										data:*, isValid:Boolean, attributes:Object)
		{
			this.controller = controller;
			_id = id;
			_path = path;
			_paths = paths;
			_strict = strict;
			_links = links;
			_strict = strict;
			_enabled = enabled;
			_data = data;
			_isValid = isValid;
			_attributes = attributes;
			
			var len:int = links.length;
			
			for (var i:int = 0; i < len; ++i)
			{
				if (StateLink(links.getItemAt(i)).state == id)
				{
					_link = StateLink(links.getItemAt(i));
					break;
				}
			}
		}
		
		public function setCondition(name:String, data:*):void
		{
			var oldVal:String = controller.getCondition(this, name);
			
			if (oldVal === data)
				return;
			
			controller.setCondition(this, name, data);
		}
		
		public function getCondition(name:String):*
		{
			return controller.getCondition(this, name);
		}
		
		public function hasConditions():Boolean
		{
			return controller.hasConditions(this);
		}
		
		public function removeCondition(name:String):void
		{
			controller.removeCondition(this, name);
		}
		
		public function validateCondition(name:String = ""):Boolean
		{
			return controller.validate(this, name);
		}
		
		public function destroy():void
		{
			
		}
		
		internal function setPath(value:String):void
		{
			_path = value;
			dispatchEvent(new Event("pathChanged"));
		}
		
		internal function setIsValid(value:Boolean):void
		{
			if (value == _isValid)
				return;
			
			_isValid = value;
			
			if (hasEventListener("isValidChanged"))
				dispatchEvent(new Event("isValidChanged"));
		}
	}
}